// rsa_help
package utils

import (
	"crypto"
	"crypto/md5"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"log"
)

func RsaEncryptWithPublickKey(originalData, publickey []byte) (result []byte, err error) {
	decoded, err := base64.StdEncoding.DecodeString(string(publickey))
	if err != nil {
		log.Println(err)
		return nil, err
	}
	var pubInterface interface{}
	if pubInterface, err = x509.ParsePKIXPublicKey(decoded); err == nil {
		pub := pubInterface.(*rsa.PublicKey)
		max := (pub.N.BitLen()+7)/8 - 11

		for len(originalData) > 0 {
			var temp []byte
			if len(originalData) > max {
				temp = originalData[:max]
				originalData = originalData[max:]
			} else {
				temp = originalData[:]
				originalData = originalData[:0]
			}
			if out, err := rsa.EncryptPKCS1v15(rand.Reader, pub, temp); err == nil {
				result = append(result, out...)
			} else {
				return nil, err
			}
		}
		return result, nil
	}
	return
}

func RsaDecryptWithPrivateKey(ciphertext, privateKey []byte) (result []byte, err error) {
	decoded, err := base64.StdEncoding.DecodeString(string(privateKey))
	if err != nil {
		log.Println(err)
		return nil, err
	}
	var priInterface interface{}
	if priInterface, err = x509.ParsePKCS8PrivateKey(decoded); err == nil {
		priv := priInterface.(*rsa.PrivateKey)
		max := (priv.N.BitLen() + 7) / 8
		for len(ciphertext) > 0 {
			var temp []byte
			if len(ciphertext) > max {
				temp = ciphertext[:max]
				ciphertext = ciphertext[max:]
			} else {
				temp = ciphertext[:]
				ciphertext = ciphertext[:0]
			}
			if out, err := priv.Decrypt(rand.Reader, temp, new(rsa.PKCS1v15DecryptOptions)); err == nil {
				result = append(result, out...)
			} else {
				return nil, err
			}
		}
	}
	return
}

func RsaSignWithPrivateKey(origData, private []byte) ([]byte, error) {
	decoded, err := base64.StdEncoding.DecodeString(string(private))
	if err != nil {
		log.Println(err)
		return nil, err
	}
	privinterface, err := x509.ParsePKCS8PrivateKey(decoded)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	resbyte := md5.Sum(origData)
	priv := privinterface.(*rsa.PrivateKey)
	return rsa.SignPKCS1v15(nil, priv, crypto.MD5, resbyte[:])
}

func RsaSignWithPrivateKeyUseBase64(origData, private []byte) ([]byte, error) {
	decoded, err := base64.StdEncoding.DecodeString(string(private))
	if err != nil {
		log.Println(err)
		return nil, err
	}
	privinterface, err := x509.ParsePKCS8PrivateKey(decoded)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	resbyte := md5.Sum(origData)
	priv := privinterface.(*rsa.PrivateKey)
	res, err := rsa.SignPKCS1v15(nil, priv, crypto.MD5, resbyte[:])

	coder := base64.NewEncoding(base64Table)
	return []byte(coder.EncodeToString(res)), err
}

/*func RsaEncryptWithPrivateKey(originalData, privatekey []byte) ([]byte, error) {
	decoded, err := base64.StdEncoding.DecodeString(string(publicKey))
	if err != nil {
		log.Println(err)
		return nil, err
	}
	privInterface, err := x509.ParsePKCS1PrivateKey(decoded)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	priv := privInterface.(*rsa.PrivateKey)

	return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
}*/
